package cn.sdormitory.service.impl;


import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
import cn.hutool.core.collection.CollectionUtil;
import cn.sdormitory.basedata.dao.BStudentDao;
import cn.sdormitory.basedata.entity.BStudent;
import cn.sdormitory.common.dto.ResultMsg;
import cn.sdormitory.common.exception.ApiException;
import cn.sdormitory.common.exption.SysExceptionEnum;
import cn.sdormitory.common.utils.BeanUtils;
import cn.sdormitory.common.utils.JwtTokenUtil;
import cn.sdormitory.common.utils.SysUserUtils;
import cn.sdormitory.login.AppTeacherDetails;
import cn.sdormitory.service.AppUserService;
import cn.sdormitory.service.ParentTokenService;
import cn.sdormitory.service.StudentTokenService;
import cn.sdormitory.sys.dao.SysUserDao;
import cn.sdormitory.sys.entity.SysMenu;
import cn.sdormitory.sys.entity.SysUser;
import cn.sdormitory.sys.service.OnlineUserService;
import cn.sdormitory.sys.service.SysMenuService;
import cn.sdormitory.sys.service.SysUserService;
import cn.sdormitory.sys.vo.LoginInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @创建人：zhouyang
 * @创建时间：2020/12/25 11:15
 * @version：V1.0
 */
@Service
@Slf4j
public class AppUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements AppUserService {
    @Resource
    private SysUserDao sysUserDao;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Resource
    private BStudentDao bStudentDao;
    @Resource
    private StudentTokenService studentTokenService;
    @Resource
    private ParentTokenService parentTokenService;
    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private OnlineUserService onlineUserService;

    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysMenuService sysMenuService;

    @Resource
    private WxMaService wxMaService;


    @Override
    public ResultMsg loginByOpenId(String loginCode, HttpServletRequest request) {
        if (StringUtils.isBlank(loginCode)) {
            return ResultMsg.BY_FAIL("code不能为空");
        }

        try {
            String openid = wxMaService.getUserService().getSessionInfo(loginCode).getOpenid();
            //教师登录
            LoginInfoVo loginInfoVo = new LoginInfoVo();
            LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(SysUser::getStatus,1);
            userWrapper.eq(SysUser::getAppOpenId,openid);
            SysUser sysUser = sysUserDao.selectOne(userWrapper);
            if(sysUser != null) {
                List<SysMenu> permissions = sysMenuService.selectMenuList(sysUser.getId());
                AppTeacherDetails userDetails = new AppTeacherDetails(sysUser, permissions);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                String token = jwtTokenUtil.generateToken(userDetails.getUsername());
                onlineUserService.save(sysUser, token, jwtTokenUtil.getExpiration(), request);
                log.info(SysUserUtils.getSysUser()+"");
                loginInfoVo = getLoginInfo(sysUser.getPhone());
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(sysUser.getPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            //学生登录
            LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
            studentWrapper.eq(BStudent::getIsGraduated,'0');
            studentWrapper.eq(BStudent::getAppOpenId,openid);
            BStudent bStudent = bStudentDao.selectOne(studentWrapper);
            if(bStudent !=null) {
                String token = studentTokenService.generateToken(request.getHeader("user-agent"),bStudent);
                studentTokenService.save(token,bStudent);

                loginInfoVo.setLoginId(bStudent.getId());
                loginInfoVo.setLoginName(bStudent.getStudentName());
                loginInfoVo.setRoleName("student");
                loginInfoVo.setIdentity(bStudent);
                loginInfoVo.setWxOpenId(bStudent.getWxOpenId());
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(bStudent.getPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            //家长登录
            LambdaQueryWrapper<BStudent> parentWrapper = new LambdaQueryWrapper<>();
            parentWrapper.eq(BStudent::getIsGraduated,'0');
            parentWrapper.eq(BStudent::getParentAppOpenId,openid);
            List<BStudent> bStudentParent = bStudentDao.selectList(parentWrapper);
            if(CollectionUtil.isNotEmpty(bStudentParent)) { //学生家长
                String token = parentTokenService.generateToken(request.getHeader("user-agent"),bStudentParent.get(0));
                parentTokenService.save(token,bStudentParent.get(0));

                loginInfoVo.setLoginId(bStudentParent.get(0).getId());
                loginInfoVo.setLoginName(bStudentParent.get(0).getParentPhone());
                loginInfoVo.setRoleName("parent");
                loginInfoVo.setIdentity(bStudentParent);
                loginInfoVo.setWxOpenId(bStudentParent.get(0).getWxOpenId());
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(bStudentParent.get(0).getParentPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            return ResultMsg.BY_SUCCESS("用户不存在,请先注册！",null);
        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return ResultMsg.BY_FAIL(e.toString());
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }
    
    @Override
    public ResultMsg getUserInfoById(String loginId, HttpServletRequest request) {
        try {
            LoginInfoVo loginInfoVo = new LoginInfoVo();
            //学生登录
            LambdaQueryWrapper<BStudent> studentWrapper = new LambdaQueryWrapper<>();
            studentWrapper.eq(BStudent::getIsGraduated,'0');
            studentWrapper.eq(BStudent::getId, loginId);
            BStudent bStudent = bStudentDao.selectOne(studentWrapper);
            if(bStudent !=null) {
            
                loginInfoVo.setLoginId(bStudent.getId());
                loginInfoVo.setLoginName(bStudent.getStudentName());
                loginInfoVo.setRoleName("student");
                loginInfoVo.setIdentity(bStudent);
                loginInfoVo.setWxOpenId(bStudent.getWxOpenId());
                loginInfoVo.setPhone(bStudent.getPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            return ResultMsg.BY_SUCCESS("用户不存在,请先注册！",null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultMsg.BY_FAIL(e.toString());
        }
    }
    
    @Override
    public ResultMsg loginByPhone(String loginCode,String phoneCode, HttpServletRequest request) {
        if (StringUtils.isBlank(phoneCode)||StringUtils.isBlank(loginCode)) {
            return ResultMsg.BY_FAIL("code不能为空");
        }

        try {
            //获取openId
            String openid = wxMaService.getUserService().getSessionInfo(loginCode).getOpenid();

            WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(phoneCode);
            String phone=phoneNoInfo.getPhoneNumber();
//           String phone="17727843559";
            if (StringUtils.isBlank(phone)) {
                return ResultMsg.BY_FAIL("手机号不存在");
            }

            //用户登录
            LoginInfoVo loginInfoVo = new LoginInfoVo();
            SysUser sysUser = sysUserDao.doLogin(phone);
            if(sysUser != null) { //教师
                sysUser.setAppOpenId(openid);
                sysUserDao.updateById(sysUser);

                List<SysMenu> permissions = sysMenuService.selectMenuList(sysUser.getId());
                AppTeacherDetails userDetails = new AppTeacherDetails(sysUser, permissions);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
                String token = jwtTokenUtil.generateToken(userDetails.getUsername());
                onlineUserService.save(sysUser, token, jwtTokenUtil.getExpiration(), request);
                log.info(SysUserUtils.getSysUser()+"");
                loginInfoVo = getLoginInfo(phone);
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(phone);
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            BStudent bStudent=bStudentDao.doLoginStudent(phone);
            if(bStudent !=null) { //学生
                bStudent.setAppOpenId(openid);
                bStudentDao.updateById(bStudent);

                String token = studentTokenService.generateToken(request.getHeader("user-agent"),bStudent);
                studentTokenService.save(token,bStudent);

                loginInfoVo.setLoginId(bStudent.getId());
                loginInfoVo.setLoginName(bStudent.getStudentName());
                loginInfoVo.setRoleName("student");
                loginInfoVo.setIdentity(bStudent);
                loginInfoVo.setWxOpenId(bStudent.getWxOpenId());
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(bStudent.getPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }
            List<BStudent> bStudentParent=bStudentDao.doLoginParent(phone);
            if(CollectionUtil.isNotEmpty(bStudentParent)) { //学生家长
                for (BStudent student : bStudentParent) {
                    student.setParentAppOpenId(openid);
                    bStudentDao.updateById(student);
                }

                String token = parentTokenService.generateToken(request.getHeader("user-agent"),bStudentParent.get(0));
                parentTokenService.save(token,bStudentParent.get(0));

                loginInfoVo.setLoginId(bStudentParent.get(0).getId());
                loginInfoVo.setLoginName(bStudentParent.get(0).getParentPhone());
                loginInfoVo.setRoleName("parent");
                loginInfoVo.setIdentity(bStudentParent);
                loginInfoVo.setWxOpenId(bStudentParent.get(0).getWxOpenId());
                loginInfoVo.setToken(token);
                loginInfoVo.setPhone(bStudentParent.get(0).getParentPhone());
                return ResultMsg.BY_SUCCESS("登录成功",loginInfoVo);
            }

            return ResultMsg.BY_FAIL("用户信息不存在");

        } catch (WxErrorException e) {
            log.error(e.getMessage(), e);
            return ResultMsg.BY_FAIL(e.toString());
        } finally {
            WxMaConfigHolder.remove();//清理ThreadLocal
        }
    }

    @Override
    public String doLogin(String loginName, HttpServletRequest request) {
        SysUser sysUser = sysUserDao.doLogin(loginName);
        BStudent bStudent=bStudentDao.doLoginStudent(loginName);
        List<BStudent> bStudentParent=bStudentDao.doLoginParent(loginName);
        log.info(SysUserUtils.getSysUser()+"");
        if(null != sysUser){
            //获取登录用户信息
            SysUser user = sysUserService.getByPhone(loginName);
            if (BeanUtils.isNull(user)) {
                throw new ApiException(SysExceptionEnum.WRONG_USERNAME_OR_PASSWORD);
            }

            List<SysMenu> permissions = sysMenuService.selectMenuList(user.getId());
            AppTeacherDetails userDetails = new AppTeacherDetails(sysUser, permissions);
//            AppTeacherDetails userDetails = (AppTeacherDetails) userDetailsService.loadUserByUsername(loginName);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            String token = jwtTokenUtil.generateToken(userDetails.getUsername());
//          String token = userTokenService.generateToken(request.getHeader("user-agent"),sysUser);
//          userTokenService.save(token,sysUser);
//            SysUser user = SysUserUtils.getSysUser();
            onlineUserService.save(user, token, jwtTokenUtil.getExpiration(), request);
            log.info(SysUserUtils.getSysUser()+"");
            return token;
        }else if(null != bStudent){
            log.info(bStudent + "");
            String token = studentTokenService.generateToken(request.getHeader("user-agent"),bStudent);
            studentTokenService.save(token,bStudent);
            return token;
        }else if(CollectionUtil.isNotEmpty(bStudentParent)){
            String token = parentTokenService.generateToken(request.getHeader("user-agent"),bStudentParent.get(0));
            parentTokenService.save(token,bStudentParent.get(0));
            return token;
        }else{
            return null;
        }
    }

    @Override
    public SysUser getUserById(int id) {
        return sysUserDao.selectById(id);
    }

    @Override
    public boolean updatePassword(int id, String oldPassword, String newPassword) {
        String loginPassword = sysUserDao.getLoginPassword(id);
        if(null != loginPassword && !"".equals(loginPassword)){
            System.out.println(loginPassword+oldPassword + "---"+passwordEncoder.matches(oldPassword,loginPassword));
            if(passwordEncoder.matches(oldPassword,loginPassword)){
                if(sysUserDao.updatePassword(id, passwordEncoder.encode(newPassword))>0){
                    return true;
                }
                return false;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    @Override
    public int getRoleCount(int id) {
        return sysUserDao.getRoleCount(id);
    }

    @Override
    public int getRoleTeaCount(int id) {
        return sysUserDao.getRoleTeaCount(id);
    }

    @Override
    public LoginInfoVo getLoginInfo(String loginName) {
        return sysUserDao.getLoginInfo(loginName);
    }

    @Override
    public List<SysUser> listAllUser() {
        return null;
    }

    @Override
    public List<SysUser> getAllClassTeacherList() {
        return sysUserDao.getClassTeacherList();
    }

    @Override
    public List<SysUser> getAllCourseInstructorList() {
        return sysUserDao.getCourseInstructorList();
    }

    @Override
    public int resetPwd(Map<String, String> map) {
        String oldPassWord = map.get("oldPassWord");
        String loginName = map.get("loginName");

        SysUser sysUser = sysUserDao.doLogin(loginName);

        boolean matches = passwordEncoder.matches(oldPassWord, sysUser.getPassword());
        if(!matches){
            return -1;
        }
        String newPassWord = map.get("newPassWord");
        String repeatNewPassWord = map.get("repeatNewPassWord");
        if(!newPassWord.equals(repeatNewPassWord)){
            return -2;
        }

        // 新密码
        String newPass = passwordEncoder.encode(newPassWord);
        SysUser user = new SysUser();
        user.setPassword(newPass);
        user.setId(sysUser.getId());
        return this.baseMapper.updateById(user);
    }
}
